#ifndef CENGINE_H
#define CENGINE_H

#include <QObject>
#include <QDeclarativeEngine>
#include "ccuisine.h"
#include "cingredient.h"
#include "cmethod.h"
#include "crecipe.h"
#include "cregion.h"
#include "ctechnique.h"
#include "ccuisinemodel.h"
#include "crecipemodel.h"
#include "cflavour.h"
#include "cdishtype.h"
#include "cfoodtype.h"
#include "crecipeingredient.h"
#include "cunittype.h"
#include "ctip.h"
#include "cconsumenutrition.h"
#include "cnutritionconsume.h"
#include "cnutrition.h"
#include "cobject.h"
#include "cingredientcategory.h"
#include "ccuisinerecipe.h"

class CEngine : public QObject
{
    Q_OBJECT
public:
    CEngine();
    virtual ~CEngine();
    /**
     * Get cuisine by cuisine id
     * @param cuisineId cuisine id
     * @return CCuisine*, valid is true if found or false
     */
    Q_INVOKABLE QObject* cuisine(int cuisineId);

    /**
     * Add cuisine
     * @param cuisine CCuisine* object, ownership is not transferred
     * @return added cuisine id, > 0 if success or -1
     */
    Q_INVOKABLE int addCuisine(QObject* cuisine);
//    Q_INVOKABLE void delCuisine(int cuisineId);

    /**
     * Get cuisine recipe by cuisine recipe id
     * @param cuisineRecipeId cuisine recipe table row id
     * @return CCuisineRecipe*, valid is true if found or false
     */
    Q_INVOKABLE QObject* cuisineRecipe(int cuisineRecipeId);

    /**
     * Add cuisine recipe
     * @param cuisineRecipe CCuisineRecipe* object, ownership is not transferred
     * @return added cuisine recipe id, > 0 if success or -1
     */
    Q_INVOKABLE int addCuisineRecipe(QObject* cuisineRecipe);

    /**
     * Get region by region id
     * @param regionId region id
     * @return CRegion*, valid is true if found or false
     */
    Q_INVOKABLE QObject* region(int regionId);
//    Q_INVOKABLE void delRegion(int regionId);
    /**
     * Add region
     * @param region CRegion* object, ownership is not transferred
     * @return added region id, > 0 if success or -1
     */
    Q_INVOKABLE int addRegion(QObject* region);

    /**
     * Get all region from the database
     * @return QObjectList with QObject type of CRegion
     */
    Q_INVOKABLE QObjectList getAllRegion();


    /**
     * Get ingredient by ingredient id
     * @param ingredientId ingredient id
     * @return CIngredient*, valid is true if found or false
     */
    Q_INVOKABLE QObject* ingredient(int ingredientId);

    /**
     * Get all ingredient from the database
     * @return QObjectList with QObject type of CIngredient
     */
    Q_INVOKABLE QObjectList getAllIngredient();

    /**
     * Add ingredient
     * @param ingredient CIngredient* object, ownership is not transferred
     * @return added ingredient id, > 0 if success or -1
     */
    Q_INVOKABLE int addIngredient(QObject* ingredient);

    /**
     * Get ingredient by ingredient id
     * @param ingredientCatId ingredient category id
     * @return CIngredientCategory*, valid is true if found or false
     */
    Q_INVOKABLE QObject* ingredientCategory(int ingredientCatId);

    /**
     * Add ingredient
     * @param ingredientCat CIngredientCategory* object, ownership is not transferred
     * @return added ingredient category id, > 0 if success or -1
     */
    Q_INVOKABLE int addIngredientCategory(QObject* ingredientCat);


    /**
     * Get recipe ingredient list by recipe id
     * @param recipeId recipeId id
     * @return QObjectList with QObject type of CRecipeIngredient
     */
    Q_INVOKABLE QObjectList recipeIngredients(int recipeId);
//    Q_INVOKABLE void deleIngredient(int regredientId);

    /**
     * Get recipe ingredient by recipe ingredient id
     * @param recipeIngredientId recipe ingredient id
     * @return CRecipeIngredientId*, valid is true if found or false
     */
    Q_INVOKABLE QObject* recipeIngredient(int recipeIngredientId);

    /**
     * Add recipe ingredient
     * @param recipeIngredient CRecipeIngredient* object, ownership is not transferred
     * @return added recipe ingredient id, > 0 if success or -1
     */
    Q_INVOKABLE int addRecipeIngredient(QObject* recipeIngredient);

    /**
     * Get method list by recipe id
     * @param recipeId recipeId id
     * @return QObjectList with QObject type of CMethod
     */
    Q_INVOKABLE QObjectList methods(int recipeId);

    /**
     * Get method by method id
     * @param methodId method id
     * @return CMethod*, valid is true if found or false
     */
    Q_INVOKABLE QObject* method(int methodId);

    /**
     * Get method by recipe id and step
     * @param recipeId recipeId id
     * @param step step of the method
     * @return CMethod*, valid is true if found or false
     */
    Q_INVOKABLE QObject* method(int recipeId, int step);
//    Q_INVOKABLE void delMethod(int methodId);

    /**
     * Add method
     * @param method CMethod* object, ownership is not transferred
     * @return added method id, > 0 if success or -1
     */
    Q_INVOKABLE int addMethod(QObject* method);

    /**
     * Get tip list by recipe id
     * @param recipeId recipeId id
     * @return QObjectList with QObject type of CTip
     */
    Q_INVOKABLE QObjectList tips(int recipeId);

    /**
     * Get tip by tip id
     * @param tipId tip id
     * @return CTip*, valid is true if found or false
     */
    Q_INVOKABLE QObject* tip(int tipId);

    /**
     * Add tip
     * @param tip CTip* object, ownership is not transferred
     * @return added tip id, > 0 if success or -1
     */
    Q_INVOKABLE int addTip(QObject* tip);

    /**
     * Get flavour by flavour id
     * @param flavourId flavour id
     * @return CFlavour*, valid is true if found or false
     */
    Q_INVOKABLE QObject* flavour(int flavourId);

    /**
     * Add flavour
     * @param flavour CFlavour* object, ownership is not transferred
     * @return added flavour id, > 0 if success or -1
     */
    Q_INVOKABLE int addFlavour(QObject* flavour);

    /**
     * Get food type by food type id
     * @param foodTypeId food type id
     * @return CFoodType*, valid is true if found or false
     */
    Q_INVOKABLE QObject* foodType(int foodTypeId);

    /**
     * Add food type
     * @param foodType CFoodType* object, ownership is not transferred
     * @return added food type id, > 0 if success or -1
     */
    Q_INVOKABLE int addFoodType(QObject* foodType);

    /**
     * Get dish type by dish type id
     * @param dishTypeId dish type id
     * @return CDishType*, valid is true if found or false
     */
    Q_INVOKABLE QObject* dishType(int dishTypeId);

    /**
     * Add dish type
     * @param dishType CDishType* object, ownership is not transferred
     * @return added dish type id, > 0 if success or -1
     */
    Q_INVOKABLE int addDishType(QObject* dishType);

    /**
     * Get recipe by recipe id
     * @param recipeId recipe id
     * @return CRecipe*, valid is true if found or false
     */
    Q_INVOKABLE QObject* recipe(int recipeId);
//    Q_INVOKABLE void delRecipe(int recipeId);

    /**
     * Add recipe
     * @param recipe CRecipe* object, ownership is not transferred
     * @return added recipe id, > 0 if success or -1
     */
    Q_INVOKABLE int addRecipe(QObject* recipe);

    /**
     * Get technique by technique id
     * @param techniqueId technique id
     * @return CTechnique*, valid is true if found or false
     */
    Q_INVOKABLE QObject* technique(int techniqueId);
//    Q_INVOKABLE void delTechnique(int techniqueId);

    /**
     * Add technique
     * @param technique CTechnique* object, ownership is not transferred
     * @return added technique id, > 0 if success or -1
     */
    Q_INVOKABLE int addTechnique(QObject* technique);

    /**
     * Get unit type by unit type id
     * @param unitTypeId unit type id
     * @return CUnitType*, valid is true if found or false
     */
    Q_INVOKABLE QObject* unitType(int unitTypeId);

    /**
     * Get all unit type from database
     * @return QObjectList contains CUnitType*
     */
    Q_INVOKABLE QStringList getAllUnitType();

    /**
     * Add unit type
     * @param unitType CUnitType* object, ownership is not transferred
     * @return added unit type id, > 0 if success or -1
     */
    Q_INVOKABLE int addUnitType(QObject* unitType);

    /**
     * Get nutrition by nutrition id
     * @param nutritionId nutrition id
     * @return CNutrition*, valid is true if found or false
     */
    Q_INVOKABLE QObject* nutrition(int nutritionId);

    /**
     * Add nutrition
     * @param nutrition CNutrition* object, ownership is not transferred
     * @return added nutrition id, > 0 if success or -1
     */
    Q_INVOKABLE int addNutrition(QObject* nutrition);

    /**
     * Get nutrition consume by nutritionConsume id
     * @param nutritionConsumeId nutrition consume id
     * @return CNutritionConsume*, valid is true if found or false
     */
    Q_INVOKABLE QObject* nutritionConsume(int nutritionConsumeId);

    /**
     * Add nutrition consume
     * @param nutritionConsume CNutritionConsume* object, ownership is not transferred
     * @return added nutrition consume id, > 0 if success or -1
     */
    Q_INVOKABLE int addNutritionConsume(QObject* nutritionConsume);

    /**
     * Get consume nutrition by nutrition consume id
     * @param nutritionConsumeId nutrition consume id
     * @return QObjectList with QObject type of CConsumeNutrition
     */
    Q_INVOKABLE QObjectList consumeNutrition(int nutritionConsumeId);

    /**
     * Add consume nutrition
     * @param consumeNutrition CConsumeNutrition* object, ownership is not transferred
     * @return added consume nutrition id, > 0 if success or -1
     */
    Q_INVOKABLE int addConsumeNutrition(QObject* consumeNutrition);

    /**
     * Get related cuisine model by parent cuisine id. The
     * returned cuisine model is singleton.
     * @param parentId parent cuisine id, -1 for root cuisine
     * @return CCuisineModel*
     */
    Q_INVOKABLE QObject *cuisineModel(int parentId);

    /**
     * Get recipe model by cuisine id. The returned recipe model
     * is singleton
     * @param cuisineId Parent cuisine id
     * @return CRecipeModel*
     */
    Q_INVOKABLE QObject *recipeModel(int cuisineId);

    /**
     * Test whether child cuisine is available
     * @param cuisineId Cuisine Id
     * @return true if has child cuisine else false
     */
    Q_INVOKABLE bool hasChildCuisine(int cuisineId);

    /**
     * Get child cuisine count
     * @param cuisineId Cuisine Id
     * @return Child cuisine count
     */
    Q_INVOKABLE int childCuisineCount(int cuisineId);


private:
    QString pictureFolderPath();
    QString installPath();
    void fillMethod(CMethod& method, QSqlQuery& sqlQuery);

    class InsertHelper {
    public:
        InsertHelper(const QString& tableName);
        void setTable(const QString& tableName);
        bool sql(QString& sqlString);
        void addNull(const QString& column);
        void addValue(const QString& column, const QString& value);
        void addValue(const QString& column, const int& value);
        void addValue(const QString& column, const double& value);
        void addValue(const QString& column, const bool& value);
    private:
        QString m_table_name;
        QString m_columns;
        QString m_values;
    };

private:
    /**
     * Query data specified by sqlStr
     * @param sqlStr SELECT or INSERT like SQL string
     * @param nonSelect false for SELECT string, true for UPDATE, INSTERT like string
     * @return QSqlQuery* if find data or NULL
     */
    QSqlQuery *query(QString &sqlStr, bool nonSelect = false);
    int initDb();
    void addDummyData();
    bool createCuisineTable();
    bool createRecipeTable();
    bool createRegionTable();
    bool createFlavourTable();
    bool createIngredientTable();
    bool createTechniqueTable();
    bool createDishTypeTable();
    bool createFoodTypeTable();
    bool createMethodTable();
    bool createRecipeIngredientTable();
    bool createUnitTypeTable();
    bool createCuisineRecipeTable();
    bool createNutritionTable();
    bool createIngredientNutritionTable();
    bool createNutritionConsumeTable();
    bool createConsumeNutritionTable();
    bool createMealTable();
    bool createMealRecipeTable();
    bool createTipsTable();
    bool createIngredientCategoryTable();
    bool createTable(QString &sql);
    QString DatabaseName();

signals:
//    void cuisineSaved()

private:
//    CRegion* m_newRegion;
//    CCuisineModel *m_cuisineModel;
//    CRecipeModel *m_recipeModel;
//    CCuisine *m_cuisine;
//    CRecipe *m_recipe;
};

#endif // CENGINE_H
